<?php

/**
 * Created by PhpStorm.
 * Author: ls
 * Time: 2023/12/29 10:10
 * Desc: 景点订单处理
 */
class Model_Spot_Service_Order extends Contract_Order
{
    /**
     * 预订的规则的套餐信息
     */
    private $rule_ticket;

    /**
     * 产品信息
     */
    private $product;

    /**
     * 总金额
     */
    private $total_price;

    /**
     * 总订金
     */
    private $total_deposit = 0;

    /**
     * 产品类型id
     * @var int
     */
    private $type_id;

    /**
     * 会员信息
     * @var mixed
     */
    private $member_info;

    /**
     * 预订数量（单个套餐规格）
     * @var int
     */
    private $single_num = 0;

    /**
     * 使用日期
     * @var string
     */
    private $use_date;

    /**
     * 单价（用于单套餐使用）
     * @var string
     */
    private $single_price = 0;

    /**
     * 是否使用会员折扣
     */
    public $use_member_discount = true;

    /**
     * 拼团信息
     * @var array
     */
    public $together_info = array();

    /**
     * 秒杀信息
     * @var array
     */
    public $seckill_info = array();

    /**
     * 优惠券信息
     */
    public $coupon_info = array();

    /**
     * 预订的规则的套餐信息
     */
    public function __construct($params)
    {
        $this->set_request_params($params);

        $this->type_id = Model_Spot::$typeid;

        $this->member_info = $params['member_info'];
    }

    /**
     * 订单验证
     * @return $this
     * @throws Exception
     */
    public function order_check()
    {
        $this->check_product();
        $this->check_user();
        $this->check_tourer();
        $this->check_price_stock();

        // 拼团
        if (!empty($this->request_params['together_id']) || !empty($this->request_params['join_id'])) {
            $this->check_together();
        }

        // 秒杀
        if (!empty($this->request_params['seckill_id'])) {
            $this->check_seckill();
        }

        return $this;
    }

    /**
     * 产品验证
     * @return $this
     * @throws Exception
     */
    public function check_product()
    {
        $info = DB::select()
            ->from('spot')
            ->where('id', '=', $this->request_params['product_id'])
            ->where('ishidden', '=', 0)
            ->execute()
            ->current();
        if (empty($info)) {
            throw new Exception('景点不存在');
        }
        $this->product                   = $info;
        $this->order_info['productaid']  = $info['aid'];
        $this->order_info['productname'] = $info['title'];
        $this->order_info['litpic']      = $info['litpic'];
        // 检查套餐
        $this->request_params['book_list'] = json_decode($this->request_params['book_list'],true);
        $book_list = is_array($this->request_params['book_list']) ? $this->request_params['book_list'] : '';
        if (empty($book_list)) {
            throw new Exception('预订套餐为空');
        }

        if ($info['is_open_multiple_ticket'] != 1) {
            // 未开启多套餐预订
            if (count($book_list) > 1) {
                throw new Exception('不支持多套餐组合预订' . count($book_list));
            }
        } else {
            // 多套餐预订的预订规则套餐
            $rule_ticket_id    = $info['multiple_rule_ticket_id'] ?: $book_list[0]['suit_id'];
            $this->rule_ticket = DB::select()
                ->from('spot_ticket')
                ->where('id', '=', $rule_ticket_id)
                ->execute()
                ->current();
            // 多套餐预订不支持订金支付
            $this->rule_ticket['paytype'] = 1;
        }

        $child_orders = array();
        foreach ($book_list as $item) {
            // 套餐验证
            $ticket = Model_Spot_Ticket::get_on_sale_ticket(array('spot_id' => $this->request_params['product_id'], 'ticket_id' => $item['suit_id']));
            if (empty($ticket)) {
                throw new Exception('套餐不存在或已下架');
            }

            if (empty($this->rule_ticket)) {
                $this->rule_ticket = $ticket;
            }

            $num = $item['num'] ? intval($item['num']) : 0;
            if ($num <= 0) {
                throw new Exception('预订数量不能小于 1');
            }

            // 单个产品预订时，单个产品的数量
            $this->single_num = $num;

            // 验证预订日期
            if (empty($item['use_date'])) {
                throw new Exception('请选择预订日期');
            }

            // 不能预订过期门票
            $use_date = $item['use_date'];
            $use_time = strtotime($use_date);
            if (strtotime($use_date) < strtotime(date('Y-m-d', time()))) {
                throw new Exception('日期不正确');
            }

            // 提前时间
            $before_time = Model_Spot_Ticket::get_before_time($ticket);
            if ($before_time && $before_time > $use_time) {
                $before_time_tips = Model_Spot_Ticket::get_before_time_tips($ticket);
                throw new Exception($before_time_tips);
            }


            // 会员id限购订单数
            if($ticket['is_open_member_limit'] == 1 && $ticket['member_limit_order_num'] > 0) {
                // 检查该会员门票已预定数量
                $book_num = Model_Api_V2_Order::get_member_order_number($this->type_id, $this->member_info['mid'], array('suit_id' => $ticket['id']));
                $book_total_num = bcadd($book_num, 1, 0);
                if($book_total_num > $ticket['member_limit_order_num']) {
                    throw new Exception('【' . $ticket['title'] . '】最多可预订 ' . $ticket['member_limit_order_num'].' 次，已预订 ' . $book_num . ' 次，不可继续预订');
                }
            }

            // 每笔订单限购数量
            if($ticket['is_open_limit_order_num'] == 1 && $ticket['limit_order_num'] > 0) {
                if($num > $ticket['limit_order_num']) {
                    throw new Exception('【'.$ticket['title'].'】购买数量不能超过 ' . $ticket['limit_order_num']. ' 张');
                }
            }

            // 订金支付
            $pay_type = $this->rule_ticket['paytype'];
            $deposit  = 0;
            if ($pay_type == 2) {
                $deposit             = bcmul($this->rule_ticket['dingjin'], $item['num'], 2);
                $this->total_deposit = bcadd($deposit, $this->total_deposit, 2);
            }

            $child_orders[] = array(
                'order' => array(
                    'productautoid' => $info['id'],
                    'productaid' => $info['aid'],
                    'productname' => $info['title'],
                    'dingnum' => $item['num'],
                    'usedate' => $item['use_date'],
                    'suitid' => $item['suit_id'],
                    'suit_name' => $ticket['title'],
                    'dingjin' => $deposit,
                    'paytype' => $pay_type,
                ),
                'ticket' => $ticket,
                'tourist' => !empty($item['tourist']) ? $item['tourist'] : '',
                'sku_id' => $item['sku_id'],
            );
        }
        $this->child_orders = $child_orders;
        return $this;
    }

    /**
     * 用户信息填写验证
     * @return $this
     * @throws Exception
     */
    public function check_user()
    {
        if (empty($this->request_params['linkman'])) {
            throw new Exception('联系人不能为空');
        }

        if (empty($this->request_params['linktel'])) {
            throw new Exception('联系人电话不能为空');
        }

        // 验证电话格式是否正确
        if (!St_Validate::is_mobile($this->request_params['linktel'])) {
            throw new Exception('联系电话人格式不正确');
        }

        $fill_link_man = $this->rule_ticket['fill_link_man'];
        if ($fill_link_man) {
            $fill_link_man = $fill_link_man ? explode(',', $fill_link_man) : array();

            // 验证邮箱格式是否正确
            if (in_array('email', $fill_link_man)) {

                if (empty($this->request_params['link_email'])) {
                    throw new Exception('邮箱不能为空');
                }

                if (!St_Validate::is_email($this->request_params['link_email'])) {
                    throw new Exception('邮箱格式不正确');
                }

                $link_email = $this->request_params['link_email'];
            }
        }

        $this->order_info['linkman']   = $this->request_params['linkman'];
        $this->order_info['linktel']   = $this->request_params['linktel'];
        $this->order_info['remark']    = $this->request_params['remark'] ?? '';
        $this->order_info['linkemail'] = $link_email ?? '';

        return $this;
    }

    /**
     * 游客填写验证
     * @return $this
     * @throws Exception
     */
    public function check_tourer()
    {
        foreach ($this->child_orders as &$item) {
            $order                       = $item['order'];
            $ticket                      = $item['ticket'];
            $fill_tourer_type            = $ticket['fill_tourer_type']; // 游客信息填写方式：0-不需要，1-仅需一位，2-需要填写所有
            $fill_tourer_credential_type = $ticket['fill_tourer_credential_type']; // 游客证件选择 1 不需要证件 2 需要身份证 3 需要有效证件
            if ($fill_tourer_type != 0) {

                if (empty($item['tourist'])) {
                    throw new Exception($ticket['title'] . '需要填写游客信息');
                }

                $tourist = $item['tourist'];
                $len     = count($tourist);
                if ($fill_tourer_type == 2) {
                    if ($order['dingnum'] > $len) {
                        throw new Exception($ticket['title'] . '需要填写' . $order['dingnum'] . '名游客信息');
                    }
                }
                $need_num = $fill_tourer_type == 2 ? $order['dingnum'] : 1;

                // 游客信息填写验证
                $order_tourists = array();
                $card_repeats   = array(); // 证件号重复填写
                foreach ($tourist as $tourer) {

                    if (empty($tourer['linkman'])) {
                        throw new Exception($ticket['title'] . '游客姓名不能为空');
                    }
                    $order_tourer = array(
                        'tourername' => $tourer['linkman'],
                        'sex' => !empty($tourer['sex']) ? $tourer['sex'] : '',
                        'mobile' => !empty($tourer['mobile']) ? $tourer['mobile'] : '',
                        'cardtype' => '',
                        'cardnumber' => '',
                    );

                    // 证件号验证
                    $card_tips = $ticket['title'] . '游客[' . $tourer['linkman'] . ']';
                    if ($fill_tourer_credential_type == 2 || $fill_tourer_credential_type == 3) {
                        if (empty($tourer['cardtype'])) {
                            throw new Exception($card_tips . '证件类型不能为空');
                        }

                        if (empty($tourer['idcard'])) {
                            throw new Exception($card_tips . '证件号不能为空');
                        }

                        $card_number = $tourer['idcard'];
                        $card_type   = $tourer['cardtype'];

                        if ($fill_tourer_credential_type == 2) {
                            if ($card_type != '身份证') {
                                throw new Exception($card_tips . '证件类型不正确');
                            }
                        }

                        if ($card_type == '身份证') {
                            $card_valid = St_Validate::check_idcard($card_number);
                            if (!$card_valid) {
                                throw new Exception($card_tips . '身份证号格式不正确');
                            }

                            // 验证用户年龄限制
                            if($this->product['is_dist_people'] == 1) {
                                $this->check_tourer_age($ticket, $card_valid['birth_date']);
                            }
                        }

                        $order_tourer['cardtype']   = $card_type;
                        $order_tourer['cardnumber'] = $card_number;

                        // 证件重复填写验证
                        if (in_array($card_number, $card_repeats)) {
                            throw new Exception($card_tips . '证件号重复使用');
                        }

                        $card_repeats[] = $card_number;
                    }

                    $order_tourists[] = $order_tourer;

                    // 游客数量够了之后直接跳出循环
                    if (count($order_tourists) == $need_num) {
                        break;
                    }
                }

                $item['tourist'] = $order_tourists;
            }
        }
        return $this;
    }

    /**
     * 价格库存验证
     * @return $this
     * @throws Exception
     */
    public function check_price_stock()
    {
        foreach ($this->child_orders as &$item) {
            $ticket    = $item['ticket'];
            $price_res = $this->get_stock_price($ticket, $item['sku_id'], $item['order']['usedate']);
            if (!$price_res['status']) {
                throw new Exception($price_res['msg']);
            }
            $stock = $price_res['stock'];
            if ($stock < $item['order']['dingnum']) {
                throw new Exception($ticket['title'] . '库存不足');
            }

            $item['order']['price'] = $price_res['price'];

            if (empty($this->use_date)) {
                $this->use_date = $item['order']['usedate'];
            }
            if (empty($this->price)) {
                $this->single_price = $item['order']['price'];
            }
        }

        return $this;
    }

    /**
     * 检查拼团
     * @return $this
     * @throws Exception
     */
    private function check_together()
    {
        $together_id = $this->request_params['together_id'];
        $join_id     = Arr::get($this->request_params, 'join_id', 0);
        if (St_Functions::is_normal_app_install('together')) {
            $together_params      = array('join_id' => $join_id, 'ding_num' => $this->single_num);
            $check_order_together = Model_Api_V2_Together::check_order_together($together_id, $this->member_info['mid'], $together_params);
            if (!$check_order_together['status']) {
                throw new Exception($check_order_together['msg']);
            }
            $this->together_info = $check_order_together['data'];
            $together_price      = $this->together_info['price'];
            foreach ($this->child_orders as &$item) {
                $item['order']['price'] = $together_price['adult_price'];
            }

            // 判断拼团是否允许使用会员折扣
            if (isset($this->together_info['discount_limit'])) {
                if (!in_array(2, $this->together_info['discount_limit'])) {
                    $this->use_member_discount = false;
                }
            }
        }
        return $this;
    }


    /**
     * 检查游客年龄
     * @param $ticket
     * @param $birth_date
     * @throws Exception
     */
    private function check_tourer_age($ticket, $birth_date)
    {
        $ticket_id = $ticket['id'];

        $people_rule = Model_Spot_Ticket_People_Rule::get_ticket_people_rule($ticket_id);
        if (!empty($people_rule)) {
            // 根据身份证获取年龄
            $current_date = $people_rule['age_type'] == 1 ? date('Y-m-d') : date('Y-12-31');
            $age          = date_diff(date_create($birth_date), date_create($current_date))->y;

            $min = $people_rule['start_age_type'] == 1 ? $people_rule['start_age'] : bcadd($people_rule['start_age'], 1, 0);
            if ($age < $min) {
                throw new Exception($ticket['title'] . '购票年龄需不小于 ' . $min . ' 岁');
            }

            $max = 150; // 最大年龄不超过150
            if ($people_rule['type'] == 2) {
                // 范围内
                $max = $people_rule['end_age_type'] == 1 ? $people_rule['end_age'] : bcsub($people_rule['end_age'], 1, 0);
            }
            if ($age > $max) {
                throw new Exception($ticket['title'] . '购票年龄需不大于 ' . $max . ' 岁');
            }
        }
    }

    /**
     * 检查秒杀
     * @return $this
     * @throws Exception
     */
    private function check_seckill()
    {
        $seckill_id = $this->request_params['seckill_id'];

        if (St_Functions::is_normal_app_install('seckill')) {
            $seckill = DB::select()
                ->from('seckill')
                ->where('id', '=', $seckill_id)
                ->execute()
                ->current();
            if (!$seckill) {
                throw new Exception('秒杀活动不存在');
            }

            $status = Model_Seckill::get_seckill_num($seckill_id, $this->member_info['mid']);
            if (!$status) {
                throw new Exception('已超出秒杀活动限制次数');
            }

            // 保存原价
            $seckill['suit_original_adult_price'] = $this->single_price;

            $this->seckill_info        = $seckill;
            $this->use_member_discount = false;
        }
        return $this;
    }

    /**
     * 检查优惠券
     * @return $this
     * @throws Exception
     */
    public function check_coupon($order_info)
    {
        if(!$this->request_params['coupon_id']){
            return $this;
        }
        $this->order_info['price'] = $order_info['price'];
        $this->coupon_info = Model_Api_V2_Coupon::order_use_coupon_check($this->request_params['coupon_id'], $this->member_info['mid'], $this->order_info);
        return $this;
    }

    /**
     * 获取库存价格
     * @param $ticket
     * @param $sku_id
     * @param $use_date
     * @return array
     */
    private function get_stock_price($ticket, $sku_id, $use_date)
    {
        try {
            $ticket_price = DB::select()
                ->from('spot_ticket_price')
                ->where('ticketid', '=', $ticket['id'])
                ->and_where('sku_id', '=', $sku_id)
                ->and_where('is_open', '=', 1)
                ->and_where('day', '=', strtotime($use_date))
                ->and_where('supplier_channel_id', '=', 1)
                ->execute()
                ->current();
            if (empty($ticket_price)) {
                throw new Exception('预订日期库存不存在');
            }
            $total_stock            = DB::select()->from('spot_ticket_stock')
                ->where('ticket_id', '=', $ticket['id'])
                ->and_where('start_day', '<=', strtotime($use_date))
                ->and_where('end_day', '>=', strtotime($use_date))
                ->execute()->get('stock');
            $ticket_price['number'] = $total_stock ?: $ticket_price['number'];

            $params        = $this->request_params;
            $stock_service = new Service_Spot_Ticket_Stock();
            $stock         = $stock_service->get_stock_limit($ticket, $ticket_price['number'], $use_date, $params);
            return array(
                'status' => true,
                'price'  => $ticket_price['adultprice'],
                'stock'  => $stock
            );
        } catch (Exception $e) {
            return array(
                'status' => false,
                'msg'    => $e->getMessage()
            );
        }
    }

    /**
     * 设置订单信息
     * @return $this|mixed
     * @throws Exception
     */
    public function set_order_data()
    {
        $this->set_parent_order();
        $this->set_child_order_data();

        //积分抵现
        if ($this->request_params['needjifen'] && $this->request_params['mid']) {
            $jifentprice = Model_Jifen_Price::calculate_jifentprice($this->product['jifentprice_id'], Model_Spot::$typeid, $this->request_params['needjifen'], $this->member_info);
            if ($jifentprice) {
                $this->order_info['jifentprice'] = $jifentprice;
                $this->order_info['usejifen']    = 1;
                $this->order_info['needjifen']   = $this->request_params['needjifen'];
            } else {
                throw new Exception('积分抵现不可用');
            }
        }

        $this->order_info['jifenbook'] = $this->product['jifenbook_id'];
        $this->order_info['haschild']  = 1;
        $this->order_info['price']     = $this->total_price;
        $this->order_info['usedate']   = $this->use_date;

        return $this;
    }

    /**
     * 设置公共部分
     * @return void
     */
    private function set_parent_order()
    {
        $this->order_info['webid']  = 0;
        $this->order_info['typeid'] = $this->type_id;

        $this->order_info['suit_name'] = '';
        $this->order_info['addtime']   = time();

        $pay_type                    = $this->rule_ticket['paytype'];
        $this->order_info['paytype'] = $pay_type;
        $this->order_info['dingjin'] = $this->total_deposit;

        $this->order_info['childprice']   = 0;
        $this->order_info['childnum']     = 0;
        $this->order_info['oldprice']     = 0;
        $this->order_info['oldnum']       = 0;
        $this->order_info['pay_way']      = $this->rule_ticket['pay_way'];
        $this->order_info['need_confirm'] = $this->rule_ticket['need_confirm'];
        $this->order_info['status']       = $this->rule_ticket['need_confirm'] ? 0 : 1;

        // 自动关闭订单时间
        $auto_close_time = $this->rule_ticket['auto_close_time'] ?: 0;
        if ($auto_close_time) {
            $this->order_info['auto_close_time'] = $auto_close_time + time();
        }

        // 待确认时限
        $auto_confirm_time = $this->rule_ticket['auto_confirm_time'] ?: 0;
        if ($auto_confirm_time) {
            $this->order_info['auto_confirm_time'] = $auto_confirm_time + time();
        }

        //自动退款时限
        $no_confirm_refund = $this->rule_ticket['no_confirm_refund'] ?: 0;
        if ($no_confirm_refund) {
            $use_date                              = trim($this->child_orders['order'][0]['use_date']);
            $this->order_info['no_confirm_refund'] = strtotime($use_date . ' +1 day') - $no_confirm_refund;
        }

        $this->order_info['dingnum']  = 1;
        $this->order_info['suitid']   = '';
        $this->order_info['source']   = $this->request_params['source'];
        $this->order_info['memberid'] = $this->request_params['mid'];

        $comment                                = Model_Jifen::get_used_jifencomment($this->type_id);
        $this->order_info['jifencomment']       = $comment ? $comment['value'] : 0;
        $this->order_info['refund_restriction'] = $this->rule_ticket['refund_restriction'];

        $this->order_info['productautoid'] = $this->product['id'];
    }

    /**
     * 设置子订单信息
     * @return void
     */
    private function set_child_order_data()
    {
        $parent_order = $this->order_info;
        $total_price  = 0;
        foreach ($this->child_orders as &$item) {
            $order         = $item['order'];
            $price         = bcmul($order['dingnum'], $order['price'], 2);
            $total_price   = bcadd($total_price, $price, 2);
            $item['order'] = array_merge($parent_order, $order);
        }
        $this->total_price = $total_price;
    }

    /**
     * 订单完成后相关数据处理
     * @param $order_info
     * @param $extend_params
     * @return void
     */
    public function create_after($order_info, $extend_params)
    {
        // 优惠券
        if (!empty($this->coupon_info)) {
            Model_Coupon::add_coupon_order($this->coupon_info['cid'], $order_info['ordersn'], $this->coupon_info['order_total_price'], $this->coupon_info, $this->request_params['coupon_id']);
        }

        //红包
        $envelope_member_id = Arr::get($this->request_params, 'envelope_member_id', 0);
        if ($envelope_member_id) {
            if (St_Functions::is_normal_app_install('red_envelope')) {
                Model_Order_Envelope::order_use_envelope($envelope_member_id, $order_info['ordersn'], $this->type_id, $this->member_info['mid']);
            }
        }

        //秒杀过来的就添加关联订单
        if (!empty($this->seckill_info)) {
            Model_Seckill::add_seckill_order($order_info, $this->seckill_info);
        }

        // 添加拼团订单
        if (!empty($this->together_info)) {
            Model_Api_V2_Together::add_order($this->together_info, $order_info);
        }

        //订单结算信息表数据更新
        Model_Member_Order_Compute::update($order_info['ordersn']);

    }


}
